﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using System.Xml;
using System.Xml.Serialization;

namespace OrderSystem
{

    [Serializable]
    public class Order {
        public Order() { }
        public Order(OrderDetails details)
        {
            this.num = 0; this.details = details;
        }
            public Order(int num,OrderDetails details) { this.num = num;this.details = details; }
        public int num;
        public OrderDetails details;
        public int Num { get; set; }
        public OrderDetails Details { get; set; }
        public override string ToString()
        {
            return "Order"+num+":\n"+details;
        }
        public override bool Equals(object obj)
        {
            try
            {
                Order tmp = (Order)obj;
                return this.details.Equals(tmp.details);
            }
            catch (Exception)
            {

                return false;
            }
            
        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

    }
    public class OrderService {
        public OrderService() { }
        public List<Order> orderlist=new List<Order>();
        public List<Order> Orderlist { get; set; }
        public bool addOrder(Order order)
        {
            try
            {
                while (true)
                {
                    if (getOrder(order.num).LongCount() != 0) { order.num += 1; }
                    else if (getOrder(order.details).LongCount() != 0) { return false; }
                    else { break; }
                }
                orderlist.Add(order);
            }
            catch (Exception)
            {
                orderlist.Add(order);
            }
            return true;

        }
        public bool modifyOrder(int index, OrderDetails newdetails) {
            var list = this.getOrder(index);
            if (list.Count() != 0) {var mod = list.First<Order>();
                if (this.deleteOrder(mod))
                {
                    mod.details = newdetails;
                    this.addOrder(mod);
                    return true;
                }
                else { return false; }
            }
            else return false;
                
            

            
           
        }
        public bool deleteOrder(Order d)
        {
            try
            {
                int m = 0;
                for (int i = 0; i < orderlist.Count(); i++)
                {
                    if (orderlist[i].Equals(d))
                    {
                        m = i;
                        break;
                    }
                }
                if (orderlist[m].Equals(d)) { orderlist.RemoveAt(m); return true; }
                else return false;

            }
            catch (Exception)
            {

                return false;
            }
        }
            
        public IEnumerable<Order> getOrder(int index) {

                return from r in orderlist where r.num == index select r;

            
        }
        public IEnumerable<Order> getOrder(Customer customer)
        {
                return from r in orderlist where r.details.customer.Equals(customer) orderby r.details.amount descending select r;
             }
        public IEnumerable<Order> getOrder(Good good) { return from r in orderlist where r.details.good.Equals(good) orderby r.details.amount descending select r; }
        public IEnumerable<Order> getOrder(double amount) { return from r in orderlist where r.details.amount == amount orderby r.details.amount descending select r; }
        public IEnumerable<Order> getOrder(OrderDetails details) { return from r in orderlist where r.details.Equals(details) orderby r.details.amount descending select r; }
        public void sort(Comparison<Order> way) { orderlist.Sort(way); }
        public void sort() {
            orderlist.Sort((left, right) =>
{
  if (left.num > right.num)
      return 1;
  else if (left.num == right.num)
      return 0;
  else
      return -1;
}); }



        public void export(string filepath)
        {
            
            FileStream stream = new FileStream(filepath, FileMode.Create, FileAccess.Write, FileShare.None);
            XmlSerializer serializer = new XmlSerializer(typeof(OrderService));
            serializer.Serialize(stream, this);
            stream.Close();
            
        }

        public void import(string filepath)
        {

            FileStream stream = new FileStream(filepath, FileMode.Open, FileAccess.Read, FileShare.None);
            XmlSerializer serializer = new XmlSerializer(typeof(OrderService));
            OrderService m = (OrderService)serializer.Deserialize(stream);
            this.orderlist = m.orderlist;
            stream.Close();

        }


    }
    [Serializable]
    public class OrderDetails
    {
        public OrderDetails() { }
        public OrderDetails(Good good, Customer customer, double amount) { this.good = good; this.customer = customer; this.amount = amount; }
        public Good good;
        public Customer customer;
        public double amount;

        public Good Good { get; set; }
        public Customer Customer { get; set; }
        public double Amount { get; set; }
        public override string ToString()
        {

            return "OrderDtails:\n" + good + customer+"amount: "+amount+"\n";
        }
        public override bool Equals(object obj)
        {
            try
            {
                OrderDetails tmp = (OrderDetails)obj;
                return (this.good.Equals(tmp.good)) && (this.customer.Equals(tmp.customer) &&(this.amount==tmp.amount));
            }
            catch (Exception)
            {

                return false;
            }

        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
    [Serializable]
    public class Good {
        public string name;
        public Good() { }
        public Good(string name) { this.name = name; }
        public override string ToString()
        {
            return "Good:\n\tname: "+name+"\n";
        }
        public override bool Equals(object obj)
        {
            try
            {
                Good tmp = (Good)obj;
                return (this.name == tmp.name);
            }
            catch (Exception)
            {

                return false;
            }

        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }
    [Serializable]
    public class Customer {
        public string name;
        public Customer() { }
        public Customer(string name) { this.name = name; }
        public override string ToString()
        {
            return "Customer:\n\tname: " + name+"\n";
        }
        public override bool Equals(object obj)
        {
            try
            {
                Customer tmp = (Customer)obj;
                return (this.name == tmp.name);
            }
            catch (Exception)
            {

                return false;
            }

        }
        public override int GetHashCode()
        {
            return base.GetHashCode();
        }
    }

        internal class Program
    {
        static void Main(string[] args)
        {
            OrderService service = new OrderService();
            Console.WriteLine("--------------------------ADD TEST-------------------------");
            //add
            if (service.addOrder(new Order(new OrderDetails(new Good("toothpaste"),new Customer("intel"), 1499.0)))) { Console.WriteLine("Success"); } else { Console.WriteLine("Failed! Already exists!"); }
            if (service.addOrder(new Order(new OrderDetails(new Good("Core i7"), new Customer("intel"), 1799.0)))) { Console.WriteLine("Success"); } else { Console.WriteLine("Failed! Already exists!"); }
            if (service.addOrder(new Order(new OrderDetails(new Good("toothpaste"), new Customer("qualcomm"), 888.0)))) { Console.WriteLine("Success"); } else { Console.WriteLine("Failed! Already exists!"); }
            if (service.addOrder(new Order(new OrderDetails(new Good("toothpaste"), new Customer("intel"), 1499.0)))) { Console.WriteLine("Success"); } else { Console.WriteLine("Failed! Already exists!"); }
            if (service.addOrder(new Order(new OrderDetails(new Good("Ryzen5 5600x"), new Customer("amd"), 1599.0)))) { Console.WriteLine("Success"); } else { Console.WriteLine("Failed! Already exists!"); }
            if (service.addOrder(new Order(new OrderDetails(new Good("8Gen1"), new Customer("qualcomm"), 999.0)))) { Console.WriteLine("Success"); } else { Console.WriteLine("Failed! Already exists!"); }
            if (service.addOrder(new Order(new OrderDetails(new Good("new fresh air"), new Customer("nvidia"), 99999.0)))) { Console.WriteLine("Success"); } else { Console.WriteLine("Failed! Already exists!"); }
            if (service.addOrder(new Order(new OrderDetails(new Good("A15 Bionic"), new Customer("Apple"), 4299.0)))) { Console.WriteLine("Success"); } else { Console.WriteLine("Failed! Already exists!"); }
            foreach (Order d in service.orderlist) { Console.WriteLine(d); }
            Console.WriteLine("--------------------------DEL TEST-------------------------");
            //del
            if (service.deleteOrder(new Order(new OrderDetails(new Good("8Gen1"), new Customer("qualcomm"), 999.0)))) { Console.WriteLine("Success"); } else { Console.WriteLine("Failed! not exist!"); }
            foreach (Order d in service.orderlist) { Console.WriteLine(d); }

            Console.WriteLine("--------------------------MODIFY TEST-------------------------");
            //modify
            if (service.modifyOrder(6, new OrderDetails(new Good("iPhone SE 3"), new Customer("Apple"), 4299.0))) { Console.WriteLine("Success"); } else { Console.WriteLine("Failed! not exist!"); }
            if (service.modifyOrder(7, new OrderDetails(new Good("airTX 3060"), new Customer("nvidia"), 5099.0))) { Console.WriteLine("Success"); } else { Console.WriteLine("Failed! not exist!"); }

            //search
            Console.WriteLine("--------------------------SEARCH TEST-------------------------");
            Console.WriteLine("Search Customer Apple");
            foreach (Order m in service.getOrder(new Customer("Apple"))){
                Console.WriteLine(m);
            }
            Console.WriteLine("Search Good toothpaste");
            foreach (Order m in service.getOrder(new Good("toothpaste")))
            {
                Console.WriteLine(m);
            }
            Console.WriteLine("--------------------------SORT TEST-------------------------");
            Console.WriteLine("==========sort by price==========");
            service.sort((left, right) =>
            {
                if (left.details.amount < right.details.amount) { return 1; }
                else if (left.details.amount == right.details.amount) { return 0; }
                else return -1;
            });
            foreach (Order d in service.orderlist) { Console.WriteLine(d); }
            Console.WriteLine("==========sort by default==========");
            service.sort();
            foreach (Order d in service.orderlist) { Console.WriteLine(d); }

            service.export("Orderlist.xml");
            Console.ReadKey();
            Console.Clear();
            OrderService n2 = new OrderService();
            Console.WriteLine("new service n2,now print orderlist, obvious it's empty");
            n2.orderlist.ForEach(Console.WriteLine);
            Console.ReadKey();
            Console.WriteLine("now run import method and print orderlist");
            n2.import("Orderlist.xml");
            n2.orderlist.ForEach(Console.WriteLine);
            Console.ReadKey();


        }
    }
}
